package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

import language.Chinese;
import language.English;
import language.Frence;
import language.German;
import language.Japanese;
import language.LanguageLoader;
import language.Spanish;
import undoredo.AbstractCommand;
import undoredo.CommandStack;
import action.listener.DrawEdge;
import action.listener.DrawVertice;
import action.listener.EditEdgeListener;
import action.listener.EditVertexListener;
import action.listener.MoveListener;
import action.listener.SelectListener;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;

import file.handling.FileFormat;
import file.handling.OpenFile;
import file.handling.Preferences;
import file.handling.WriteFile;
import gui.menu.actions.AboutAction;
import gui.menu.actions.AdvanceAction;
import gui.menu.actions.DeleteAction;
import gui.menu.actions.ExportPDFAction;
import gui.menu.actions.ExportPNGAction;
import gui.menu.actions.HelpAction;
import gui.menu.actions.NewAction;
import gui.menu.actions.OpenAction;
import gui.menu.actions.QuitAction;
import gui.menu.actions.RedoAction;
import gui.menu.actions.SaveAction;
import gui.menu.actions.SaveAsAction;
import gui.menu.actions.SimpleAction;
import gui.menu.actions.UndoAction;
import gui.tools.actions.AddEdgeAction;
import gui.tools.actions.AddVerticeAction;
import gui.tools.actions.EditEdgeAction;
import gui.tools.actions.EditVertexAction;
import gui.tools.actions.KruskalAction;
import gui.tools.actions.NearestNeighborAction;
import gui.tools.actions.PrimAction;
import gui.tools.actions.ResetAction;


public class Frame extends JFrame
{
   private static Image icon = Toolkit.getDefaultToolkit().getImage("icons/scc.png");
   private static Action redoAction;
   /**
    * 
    */
   private static final long serialVersionUID = 1L;

   // Actions for modifying the current selection */
   private static Action undoAction;

   /** Undo Redo */
   private static CommandStack undoredo;

   public static void addCommandToStack(AbstractCommand command)
   {
      undoredo.addToStack(command);
      setUndoRedoVisible();
   }
   public static void setNativeLookAndFeel()
   {
      try
      {
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      }
      catch (Exception e)
      {
      }
   }
   public static void setUndoRedoVisible()
   {
      undoAction.setEnabled(undoredo.checkUndo());
      redoAction.setEnabled(undoredo.checkRedo());
   }
   private Action aboutAction;
   private Action advMode;
   private JMenu algoMenu;
   private Action delAction;
   private Action drawEdge;
   private Action drawVertice;
   private MouseListener edgeListener;
   private Action editEdge;
   private MouseListener editEdgeListener;
   private JMenu editMenu;
   private Action editVertex;
   private MouseListener editVertexListener;
   private JMenu export;
   private File file = null;
   private JMenu fileMenu;
   private JMenu help;
   private Action helpAction;
   private JMenu insertMenu;
   private Action kruskal;
   private JMenu language;
   private JMenuBar menuBar = new JMenuBar();
   private MouseMotionListener moveLister;
   private Action newAction;
   private Action nn;
   private Action openAction;

   private Action pdfAction;
   private Action pngAction;
   private Preferences preferences;
   private Action prim;
   private Action quitAction;
   private Action reset;
   private Action saveAction;
   private Action saveAsAction;
   private MouseListener selectLister;

   private Action simMode;

   private MouseListener vertexListener;

   private View view;
   private JMenu viewMenu;
   public Frame()
   {

      init();

      setTitle("Save Connection Costs");

      this.setIconImage(Toolkit.getDefaultToolkit().getImage("icons/scc.png"));


      view = new View();
      view.setBackground(Color.lightGray);
      getContentPane().add(view, BorderLayout.CENTER);

      preferences = new Preferences();
      selectLister = new SelectListener(view);
      moveLister = new MoveListener(view);
      vertexListener = new DrawVertice(view);
      edgeListener = new DrawEdge(view);
      editEdgeListener = new EditEdgeListener(view);
      editVertexListener = new EditVertexListener(view);

      //Add Select and Movement Listener
      view.addMouseListener(selectLister);
      view.addMouseListener((MouseListener) moveLister);
      view.addMouseMotionListener(moveLister);

      this.setJMenuBar(menuBar);
      //      file =new File("nn.xml");
      //      openFile(file);
   }
   public void AddEdgeListener()
   {
      view.addMouseListener(edgeListener);
   }
   public void addEditEdgeLister()
   {
      view.addMouseListener(editEdgeListener);
   }
   public void addEditVertexLister()
   {
      view.addMouseListener(editVertexListener);
   }
   public void AddVertexListener()
   {
      view.addMouseListener(vertexListener);
   }
   public void disableUndoRedo()
   {
      undoredo = new CommandStack();
      redoAction.setEnabled(false);
      undoAction.setEnabled(false);
   }
   public void exportPDf()
   {
      int w = view.getWidth();
      int h = view.getHeight();
      Document document = new Document(new Rectangle(view.getWidth(), view.getHeight()));

      JFileChooser dialog = new JFileChooser(getPreferences().getDefaultPath());
      dialog.showSaveDialog(null);
      File pdfoutput = dialog.getSelectedFile();

      if (pdfoutput != null)
      {
         String name = pdfoutput.getPath();
         if (!name.endsWith(".pdf"))
            pdfoutput = new File(name + ".pdf");
         if (pdfoutput.exists())
            if (JOptionPane.showConfirmDialog(getRootPane(), String
                  .format("Do you want to replace the existing file named %s?",
                        pdfoutput.getName()), "Overwrite existing file?",
                        JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION)
               return;
         try
         {
            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfoutput));
            document.open();
            PdfContentByte cb = writer.getDirectContent();
            Graphics g2 = cb.createGraphics(w, h);
            view.paint(g2);
            document.close();
         }
         catch (FileNotFoundException e)
         {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
         catch (DocumentException e)
         {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }

      }


   }

   public void exportPNG()
   {
      JFileChooser dialog = new JFileChooser(getPreferences().getDefaultPath());
      dialog.showSaveDialog(null);
      File pngoutput = dialog.getSelectedFile();
      if (pngoutput != null)
      {
         String name = pngoutput.getPath();
         if (!name.endsWith(".png"))
            pngoutput = new File(name + ".png");
         if (pngoutput.exists())
            if (JOptionPane.showConfirmDialog(getRootPane(), String
                  .format("Do you want to replace the existing file named %s?",
                        pngoutput.getName()), "Overwrite existing file?",
                        JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION)
               return;
         this.setTitle("Save Connection Cost: "+ pngoutput.getPath());
         this.getPreferences().setDefaultPath(pngoutput.getPath());

         int width = view.getWidth();
         int height = view.getHeight();
         BufferedImage bufferedImage = new BufferedImage(width, height,
               BufferedImage.TYPE_INT_RGB);
         Graphics g = bufferedImage.getGraphics();
         view.paint(g);

         try
         {
            ImageIO.write(bufferedImage, "png", pngoutput);
            setFile(pngoutput);
         }
         catch (IOException e)
         {
            JOptionPane.showMessageDialog(getRootPane(), e.getMessage(),
                  "Unable to save PNG file", JOptionPane.ERROR_MESSAGE);
         }

      }
   }

   public File getFile()
   {
      return file;
   }
   public Preferences getPreferences()
   {
      return preferences;
   }



   public CommandStack getUndoRedoStack()
   {
      return undoredo;
   }

   public View getView()
   {
      return view;
   }

   private void init()
   {

      getContentPane().add(menuBar, BorderLayout.NORTH);

      // Undo redo function and action command
      undoredo = new CommandStack();
      redoAction = new RedoAction(this);
      undoAction = new UndoAction(this);
      // Disable this because of null
      disableUndoRedo();

      editEdge = new EditEdgeAction(this);
      editVertex = new EditVertexAction(this);
      delAction = new DeleteAction(this);

      pdfAction = new ExportPDFAction(this);
      pngAction = new ExportPNGAction(this);
      newAction = new NewAction(this);
      openAction = new OpenAction(this);
      quitAction = new QuitAction(this);

      saveAction = new SaveAction(this);
      saveAsAction = new SaveAsAction(this);


      prim = new PrimAction(this);
      kruskal = new KruskalAction(this);
      nn = new NearestNeighborAction(this);
      reset = new ResetAction(this);

      drawVertice = new AddVerticeAction(this);
      drawEdge = new AddEdgeAction(this);

      aboutAction = new AboutAction();
      helpAction = new HelpAction(this);

      // Associate keyboard shortcuts with actions

      newAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      openAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      saveAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      saveAsAction.putValue(
            Action.ACCELERATOR_KEY,
            KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.SHIFT_MASK
                  | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
      quitAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));

      undoAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      redoAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));

      delAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke((char) KeyEvent.VK_DELETE));

      prim.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      kruskal.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_K, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      nn.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_M, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      reset.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));

      drawVertice.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      drawEdge.putValue(Action.ACCELERATOR_KEY, KeyStroke
            .getKeyStroke(KeyEvent.VK_E, Toolkit.getDefaultToolkit()
                  .getMenuShortcutKeyMask()));
      editEdge.putValue(
            Action.ACCELERATOR_KEY,
            KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.SHIFT_MASK
                  | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
      editVertex.putValue(
            Action.ACCELERATOR_KEY,
            KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.SHIFT_MASK
                  | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
      // File sub Menus
      fileMenu = new JMenu("File");
      fileMenu.setMnemonic(KeyEvent.VK_F);
      fileMenu.add(new JMenuItem(newAction));
      fileMenu.add(new JMenuItem(openAction));
      fileMenu.add(new JMenuItem(saveAction));
      fileMenu.add(new JMenuItem(saveAsAction));
      fileMenu.add(new JMenuItem(quitAction));
      menuBar.add(fileMenu);

      //Edit sub Menu
      editMenu = new JMenu("Edit");
      editMenu.setMnemonic(KeyEvent.VK_E);
      editMenu.add(new JMenuItem(undoAction));
      editMenu.add(new JMenuItem(redoAction));
      editMenu.add(new JMenuItem(editVertex));
      editMenu.add(new JMenuItem(editEdge));
      editMenu.add(new JMenuItem(delAction));
      menuBar.add(editMenu);

      insertMenu = new JMenu("Insert");
      insertMenu.setMnemonic(KeyEvent.VK_I);
      insertMenu.add(new JMenuItem(drawVertice));
      insertMenu.add(new JMenuItem(drawEdge));
      menuBar.add(insertMenu);

      algoMenu = new JMenu("Algorithms");
      algoMenu.add(prim);
      algoMenu.add(kruskal);
      algoMenu.add(nn);
      algoMenu.add(reset);
      menuBar.add(algoMenu);

      viewMenu = new JMenu("View");
      simMode = new SimpleAction(this);
      advMode = new AdvanceAction(this);
      language = new JMenu("Language");
      Action en = new English(this);
      Action ch = new Chinese(this);
      Action de = new German(this);
      Action fr = new Frence(this);
      Action jp = new Japanese(this);
      Action sp = new Spanish(this);
      language.add(en);
      language.add(ch);
      language.add(de);
      language.add(fr);
      language.add(jp);
      language.add(sp);
      viewMenu.add(simMode);
      viewMenu.add(advMode);
      viewMenu.add(language);
      menuBar.add(viewMenu);

      export = new JMenu("Export");
      export.add(new JMenuItem(pdfAction));
      export.add(new JMenuItem(pngAction));
      menuBar.add(export);

      help = new JMenu("Help");
      help.add(new JMenuItem(helpAction));
      help.add(new JMenuItem(aboutAction));
      menuBar.add(help);

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      // getContentPane().setBackground(Color.white);

      setSize(800, 600);
      setNativeLookAndFeel();
   }

   public boolean isModified()
   {
      if (undoAction.isEnabled() || redoAction.isEnabled())
         return true;
      else
         return false;
   }

   public void NewView()
   {
      file = null;
      view.clear();
      view.repaint();
   }

   public void openFile(File file)
   {
      this.file = file;
      new OpenFile(file, this);
      this.setTitle("Save Connection Cost: "+ file.getPath());
      this.getPreferences().setDefaultPath(file.getPath());

   }

   public void removeListeners()
   {
      view.removeMouseListener(edgeListener);
      view.removeMouseListener(editEdgeListener);
      view.removeMouseListener(vertexListener);
      view.removeMouseListener(editVertexListener);
   }

   public void saveFile(File file)
   {
      JFileChooser dialog;
      //SaveAs
      if(file==null)
      {
         dialog = new JFileChooser(getPreferences().getDefaultPath());
         dialog.addChoosableFileFilter(new FileFormat());
         dialog.showSaveDialog(null);
         file = dialog.getSelectedFile();
         if (file != null)
         {
            String name = file.getPath();
            if (!name.endsWith(".xml"))
               file = new File(name + ".xml");
            if (file.exists())
               if (JOptionPane.showConfirmDialog(getRootPane(), String
                     .format("Do you want to replace the existing file named %s?",
                           file.getName()), "Overwrite existing file?",
                           JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION)
                  return;
            this.setTitle("Save Connection Cost: "+ file.getPath());
            this.getPreferences().setDefaultPath(file.getPath());
            this.file = file;
            new WriteFile(file, this);

         }

      }
      //Save action
      else
         new WriteFile(file, this);

   }

   public void setEngineerMode()
   {
      editEdge.putValue("Name", "Edit Edge");
      editVertex.putValue("Name", "Edit Vertex");
      drawEdge.putValue("Name",  "Edge");
      drawVertice.putValue("Name", "Vertex");
      advMode.setEnabled(false);
      simMode.setEnabled(true);
   }


   public void setFile(File file)
   {
      this.file = file;
   }

   public void setLanguage()
   {
      String key = "Name";
      fileMenu.setText(LanguageLoader.file);
      editMenu.setText(LanguageLoader.edit);

      insertMenu.setText(LanguageLoader.insert);
      drawEdge.putValue(key, LanguageLoader.link);
      drawVertice.putValue(key, LanguageLoader.node);
      language.setText(LanguageLoader.lang);

      newAction.putValue(key, LanguageLoader._new);
      openAction.putValue(key, LanguageLoader.open);
      saveAction.putValue(key, LanguageLoader.save);
      saveAsAction.putValue(key, LanguageLoader.saveas);
      quitAction.putValue(key, LanguageLoader.quit);

      export.setText(LanguageLoader.export);
      pngAction.putValue(key, LanguageLoader.exportPNG);
      pdfAction.putValue(key, LanguageLoader.exportPDF);

      undoAction.putValue(key, LanguageLoader.undo);
      redoAction.putValue(key, LanguageLoader.redo);
      editEdge.putValue(key, LanguageLoader.editlink);
      editVertex.putValue(key, LanguageLoader.editnode);
      delAction.putValue(key, LanguageLoader.delete);

      viewMenu.setText(LanguageLoader.view);
      simMode.putValue(key, LanguageLoader.simple);
      advMode.putValue(key, LanguageLoader.advance);

      help.setText(LanguageLoader.help);
      helpAction.putValue(key, LanguageLoader.help);
      aboutAction.putValue(key, LanguageLoader.about);
      advMode.setEnabled(true);
      simMode.setEnabled(true);
   }
   public void setSimpleMode()
   {
      editEdge.putValue("Name", "Edge connector");
      editVertex.putValue("Name", "Edit Node");
      drawEdge.putValue("Name",  "Connector");
      drawVertice.putValue("Name", "Node");
      simMode.setEnabled(false);
      advMode.setEnabled(true);

   }
   public void setView(View v)
   {
      view = v;
      view.setBackground(Color.blue);
   }
}
